The code requires several modules for DNS operations and uses custom functions from a module named ../Core
to perform tasks such as creating a Google Cloud DNS managed zone and inserting an address. The createZone
function creates or retrieves a managed zone with a given subdomain, while the insertAddress
function attempts to insert an address into the DNS managed zone.
npm run import -- "check dns"
var dns = require('dns');
var util = require('util');
var uuid = require('uuid/v1');
var importer = require('../Core');
var authorizeGoogle = importer.import("authorize google service");
var {listGlobalForwards} = importer.import("list google bucket url map");
var waitForOperation = importer.import("wait cloud operation");
var host = 'sheet-to-web.com';
function safeName(name) {
return name.replace(/[^a-z0-9\-]/ig, '-').substr(0, 50).toLowerCase();
}
function createZone(client, project, subdomain) {
var zone;
return client.request({
url: `https://www.googleapis.com/dns/v1/projects/${project}/managedZones`,
params: {
dnsName: subdomain.includes(host) ? (host + '.') : (subdomain + '.')
}
})
.then(res => {
if(res.data.managedZones.length > 0) {
zone = res.data.managedZones[0].name;
console.log(`Zone ${subdomain} already mapped`);
return Promise.resolve(res.data.managedZones[0].name);
}
zone = 'mz-' + uuid().substr(0, 5) + '-' + safeName(subdomain);
console.log(`Creating a zone for ${subdomain}`)
return client.request({
method: 'POST',
url: `https://www.googleapis.com/dns/v1/projects/${project}/managedZones`,
data: {
name: zone,
dnsName: subdomain + '.',
description: '',
visibility: 'public',
dnssecConfig: {
state: 'on',
kind: 'dns#managedZoneDnsSecConfig'
}
}
})
})
.then(() => zone)
}
function insertAddress(client, project, addrs, subdomain) {
var zone;
var name = 'ip-' + uuid().substr(0, 5) + '-' + safeName(subdomain);
var address;
var records;
var defaultRecord;
return createZone(client, project, subdomain)
// TODO: check for unused ips
.then(z => (zone = z))
.then(() => {
return client.request({
url: `https://www.googleapis.com/dns/v1/projects/${project}/managedZones/${zone}/rrsets`
})
})
.then(res => {
defaultRecord = res.data.rrsets.filter(r => r.type == 'A' && r.name == host + '.')[0];
records = res.data.rrsets.filter(r => r.type == 'A' && r.name == subdomain + '.');
})
// check if there is an ip unassigned
.then(() => listGlobalForwards(project))
.then(forwards => {
// match existing dns records
var match = Object.keys(addrs)
// use sheet-to-web host ip address
.filter(a => subdomain.includes(host)
? defaultRecord.rrdatas[0] == addrs[a]
: records.filter(r => r.rrdatas[0] == addrs[a]).length > 0)
if(match.length > 0) {
name = match[0];
address = addrs[match[0]];
console.log(`Matched IP ${match[0]} already exists`);
return Promise.resolve(match[0]);
}
var unused = Object.keys(addrs)
.filter(a => Object.values(forwards)
.map(gf => gf.IPAddress)
.filter(ip => ip == addrs[a]).length == 0);
if(unused.length > 0) {
name = unused[0];
address = addrs[unused[0]];
console.log(`New unused IP ${unused[0]} already exists`);
return Promise.resolve(unused[0]);
}
console.log(`Creating address for ${subdomain}`)
return client.request({
method: 'POST',
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/addresses`,
data: {
name: name,
// ipVersion: 'IPV6',
networkTier: 'PREMIUM'
}
})
.then(res => {
return waitForOperation(res.data.selfLink);
})
.then(target => {
return client.request({
url: target
})
})
.then(res => {
address = res.data.address;
})
})
// update zone with A record
.then(() => {
return client.request({
method: 'POST',
url: `https://www.googleapis.com/dns/v1/projects/${project}/managedZones/${zone}/changes`,
data: {
additions: [
{
kind: 'dns#resourceRecordSet',
name: subdomain + '.',
type: 'A',
ttl: 3600,
rrdatas: [address]
}
],
deletions: records
}
})
})
.then(() => name)
/*
{
"kind": "dns#resourceRecordSet",
"name": "example.com.",
"rrdatas": [
"1.2.3.4"
],
"ttl": 86400,
"type": "A"
}
AAAA
IPv6 Address record, which is used to map a host name to an IPv6 address.
Example of the resource record set representation:
{
"kind": "dns#resourceRecordSet",
"name": "example.com.",
"rrdatas": [
"2607:f8b0:400a:801::1005"
],
"ttl": 86400,
"type": "AAAA"
}
*/
}
function addIP(project, subdomain) {
var client, addresses;
return util.promisify(dns.lookup)(subdomain)
.then((addrs, family) => {
addresses = [addrs.address];
})
.catch(up => {
if(up.message.includes('ENOTFOUND')) {
addresses = [];
console.log(up.message);
return;
}
throw up
})
.then(() => authorizeGoogle())
.then(c => (client = c).request({
url: `https://www.googleapis.com/compute/v1/projects/${project}/global/addresses`,
}))
.then(res => {
return (res.data.items || []).reduce((obj, addr) => {
obj[addr.name] = addr.address;
return obj
}, {});
})
.then(addrs => {
var matching = Object.keys(addrs).filter(a => addresses.indexOf(addrs[a]) > -1);
if(matching.length > 0) {
console.log(`domain ${subdomain} already exists, ip address ${matching[0]}`)
return Promise.resolve(matching[0]);
}
return insertAddress(client, project, addrs, subdomain);
});
}
module.exports = addIP;
```javascript
const dns = require('dns');
const { promisify } = require('util');
const { v1: uuid } = require('uuid');
const importer = require('../Core');
const authorizeGoogle = importer.import('authorize google service');
const listGlobalForwards = importer.import('list google bucket url map');
const waitForOperation = importer.import('wait cloud operation');
const host ='sheet-to-web.com';
function safeName(name) {
if (typeof name!=='string') return '';
return name.replace(/[^a-z0-9\-]/ig, '-').substr(0, 50).toLowerCase();
}
function createZone(client, project, subdomain) {
return client.getRequest('GET', `https://www.googleapis.com/dns/v1/projects/${project}/managedZones`)
.then(res => {
if (res.data && res.data.managedZones && res.data.managedZones.length > 0) {
const zone = res.data.managedZones[0];
console.log(`Zone ${subdomain} already mapped`);
return Promise.resolve(zone.name);
}
const zoneName = `mz-${uuid().substr(0, 5)}-${safeName(subdomain)}`;
console.log(`Creating a zone for ${subdomain}`);
return client.request({
method: 'POST',
url: `https://www.googleapis.com/dns/v1/projects/${project}/managedZones`,
data: {
name: zoneName,
dnsName: subdomain + '.',
description: '',
visibility: 'public',
dnssecConfig: {
state: 'on',
kind: 'dns#managedZoneDnsSecConfig'
}
}
})
.then(() => zoneName);
});
}
function getZone(client, project, subdomain) {
return client.getRequest('GET', `https://www.googleapis.com/dns/v1/projects/${project}/managedZones`)
.then(res => {
if (res.data && res.data.managedZones && res.data.managedZones.length > 0) {
return res.data.managedZones.find(zone => zone.dnsName === subdomain + '.');
}
return null;
});
}
function insertAddress(client, project, addrs, subdomain) {
const zoneName = safeName(subdomain);
const name = `ip-${uuid().substr(0, 5)}-${zoneName}`;
let address = '';
let records = [];
return createZone(client, project, subdomain)
.then(zone => {
records = getRecords(client, project, zone.name, subdomain);
return records;
})
.then(records => {
const unusedIps = Object.keys(addrs).filter(a =>!records.some(r => r.rrdatas[0] === addrs[a]));
if (unusedIps.length > 0) {
address = addrs[unusedIps[0]];
name = unusedIps[0];
console.log(`New unused IP ${unusedIps[0]} exists`);
return Promise.resolve({ name, address });
}
const defaultRecord = records.find(r => r.type === 'A' && r.name === host + '.');
if (defaultRecord) {
address = defaultRecord.rrdatas[0];
}
return client.createResourceRecordSet(client, project, zone.name, subdomain + '.', 'A', [address]);
})
.then(() => ({ name, address }));
}
function getRecords(client, project, zoneName, subdomain) {
return client.getRequest('GET', `https://www.googleapis.com/dns/v1/projects/${project}/managedZones/${zoneName}/rrsets`)
.then(res => res.data.rrsets.filter(r => r.type === 'A' && r.name === subdomain + '.'));
}
function addIP(project, subdomain) {
const client = authorizeGoogle();
const addresses = [];
const { promisifiedLookup } = promisify(dns.lookup);
const findExistingAddress = address => address.rrdatas[0];
const findUnusedAddress = () => {
const unusedIps = Object.keys(addresses).filter(a =>!getAddresses(client, project).some(addr => findExistingAddress(addr) === addresses[a]));
return unusedIps.length > 0? unusedIps[0] : null;
};
return promisifiedLookup(subdomain)
.catch(up => {
if (up.message.includes('ENOTFOUND')) {
console.log(up.message);
return;
}
throw up;
})
.then(addrs => {
addresses.push(addrs.address);
return listGlobalForwards(project);
})
.then(forwards => {
const matching = Object.keys(forwards).filter(a => addresses.indexOf(forwards[a]) > -1);
if (matching.length > 0) {
console.log(`domain ${subdomain} already exists, ip address ${matching[0]}`);
return Promise.resolve(matching[0]);
}
return insertAddress(client, project, addresses, subdomain);
});
}
function clientRequest(client, method, url, data) {
return client.request({
method,
url,
data
});
}
function clientGetRequest(client, url) {
return client.getRequest('GET', url);
}
module.exports = addIP;
```
Code Breakdown
The code requires the following modules:
dns
for DNS operationsutil
for utility functions (not used in this code snippet)uuid/v1
for generating unique identifiers../Core
a custom module containing import functionsauthorizeGoogle
from the custom modulelistGlobalForwards
from the custom modulewaitForOperation
from the custom modulehost
: a constant string set to 'sheet-to-web.com'
safeName
: a function that takes a string, replaces non-alphanumeric characters with hyphens, truncates to 50 characters, and converts to lowercasecreateZone
: a function that creates a Google Cloud DNS managed zoneinsertAddress
: a function that inserts an address into the DNS managed zoneThe createZone
function:
subdomain
.name
: the generated unique zone namednsName
: the subdomain with a trailing dotdescription
: an empty stringvisibility
: publicdnssecConfig
: enabled with default settingsThe insertAddress
function:
createZone
to create or retrieve the managed zone for the given subdomain
.insertAddress
with the zone name and other parametersNote that the code snippet is incomplete, and the insertAddress
function is not fully implemented.